package org.twnmayberry.it;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

import java.util.Date;
import java.util.List;
import java.util.Properties;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.twndmv.bo.Color;
import org.twndmv.bo.Sex;
import org.twndmv.bo.State;
import org.twndmv.dto.PersonDTO;
import org.twndmv.dto.PhysicalDetailsDTO;
import org.twndmv.dto.ResidenceDTO;
import org.twndmv.dto.VehicleRegistrationDTO;
import org.twndmv.ejb.DmvTestUtilRemote;
import org.twndmv.ejb.DriverMgmtRemote;
import org.twndmv.ejb.PersonMgmtRemote;
import org.twndmv.ejb.VehicleMgmtRemote;
import org.twnmayberry.bo.Type;
import org.twnmayberry.dto.ActivityDTO;
import org.twnmayberry.dto.POIDTO;
import org.twnmayberry.ejb.MayberryTestUtilRemote;
import org.twnmayberry.ejb.PoiMgmtRemote;

public class MayberryEndToEndIT {
    
	private static Log log = LogFactory.getLog(MayberryEndToEndIT.class);
	private Context jndi;
	private static final String adminUser = System.getProperty("admin.user", "admin1");  
    private static final String knownUser = System.getProperty("known.user", "known");
    private static final String kathyUser = System.getProperty("kathy.user", "kathy");
    private static final String sherriUser = System.getProperty("sherri.user", "sherri");
    private static final String raleighUser = System.getProperty("raleigh.user", "sysRaleigh");
    private static final String mayberryUser = System.getProperty("mayberry.user", "sysMayberry");
    private static final String andyUser = System.getProperty("andy.user", "andy");
    private static final String barneyUser = System.getProperty("barney.user", "barney");
    private static final String gomerUser = System.getProperty("gomer.user", "gomer");
    private static final String password = System.getProperty("password", "password");

    private static final String dmvTestUtilJNDI = System.getProperty("jndi.name.dmvTestUtil",
            "twnDmvEAR/twnDmvEJB/DmvTestUtilEJB!org.twndmv.ejb.DmvTestUtilRemote");
    private static final String dmvPersonJNDI = System.getProperty("jndi.name.person",
            "twnDmvEAR/twnDmvEJB/PersonMgmtEJB!org.twndmv.ejb.PersonMgmtRemote");

    private static final String dmvVehicleJNDI = System.getProperty("jndi.name.vehicle",
            "twnDmvEAR/twnDmvEJB/VehicleMgmtEJB!org.twndmv.ejb.VehicleMgmtRemote");
    
    private static final String poiManagerJNDI = System.getProperty("jndi.name.poi",
            "twnMayberryWAR/PoiMgmtEJB!org.twnmayberry.ejb.PoiMgmtRemote");
    private static final String mayTestUtilJNDI = System.getProperty("jndi.name.mayberryTestUtil",
            "twnMayberryWAR/MayberryTestUtilEJB!org.twnmayberry.ejb.MayberryTestUtilRemote");
    private static final String dmvDriverJNDI = System.getProperty("jndi.name.driver",
            "twnDmvEAR/twnDmvEJB/DriverMgmtEJB!org.twndmv.ejb.DriverMgmtRemote"); 
    

    private DmvTestUtilRemote testUtil;
    private MayberryTestUtilRemote mayTestUtil;
    private PoiMgmtRemote poiManager;
    private VehicleMgmtRemote carManager;
    private PersonMgmtRemote personManager;
    private DriverMgmtRemote driverManager;
    
    private Context runAs(String username, String password) throws NamingException {
        if (jndi!=null) {
                jndi.close();
        }
        Properties env = new Properties();
        if (username != null) {
            env.put(Context.SECURITY_PRINCIPAL, username);
            env.put(Context.SECURITY_CREDENTIALS, password);
        }
        log.debug(String.format("%s env=%s", username==null?"anonymous":username, env));
        System.out.println(String.format("%s env=%s", username==null?"anonymous":username, env));
        jndi=new InitialContext(env);
        return jndi;
    }
    
    @Before
	public void setUp() throws Exception {
		log.debug("===== TestDmvIT.init =====");

	        jndi = runAs(adminUser, password);
	        jndi.lookup("/"); //do a quick comms check of JNDI

	        testUtil = (DmvTestUtilRemote)jndi.lookup(dmvTestUtilJNDI);
	        personManager = (PersonMgmtRemote)jndi.lookup(dmvPersonJNDI);
	        carManager = (VehicleMgmtRemote)jndi.lookup(dmvVehicleJNDI);
	        poiManager = (PoiMgmtRemote)jndi.lookup(poiManagerJNDI);
	        mayTestUtil = (MayberryTestUtilRemote)jndi.lookup(mayTestUtilJNDI);
	        driverManager = (DriverMgmtRemote)jndi.lookup(dmvDriverJNDI);

	        assertNotNull(testUtil);
	        assertNotNull(personManager);
	        assertNotNull(carManager);
	        assertNotNull(poiManager);
	        assertNotNull(mayTestUtil);
	}
    
    /**
     * It is important to close the JNDI context in between tests
     */
    @After
    public void tearDown() throws NamingException {
        if (jndi != null) {
                jndi.close();
                jndi=null;
        }
    }
    
    @Test
    public void testEndToEnd() throws NamingException {
    	log.info("===== MayberryIT.testEndToEnd ======");
    	 
    	
    	
    	testUtil.resetAll();
		testUtil.populate();
		log.info("populated DB");
		
		jndi = runAs(mayberryUser,password);
		List<PersonDTO> allDrivers = driverManager.getAllDrivers();
		log.info("There are this many drivers, holy CRAP!  " + allDrivers.size());
		assertEquals(1000, allDrivers.size());
		for(PersonDTO person : allDrivers) {
		log.debug("Person: " + person.printName());
		}
		PersonDTO testPerson = new PersonDTO();  
	    testPerson.setFirstName("Steve");
	    testPerson.setMiddleName("Danger");
	    testPerson.setLastName("Jobs");
	    PhysicalDetailsDTO testDetails = new PhysicalDetailsDTO();
	    testDetails.setHeight(64);
	    testDetails.setWeight(180);
	    testDetails.setSEX(Sex.MALE);
	    testPerson.setPhysicalDetails(testDetails);
	    jndi = runAs(kathyUser,password);
	    driverManager.addDriver(testPerson);
	    jndi = runAs(mayberryUser,password);
	    allDrivers = driverManager.getAllDrivers();
	    assertEquals(1001, allDrivers.size());
		for(PersonDTO person : allDrivers) {
		  log.debug("Person: " + person.printName());
		}
	    
	    List<PersonDTO> resultPersons = driverManager.getDriversByLastName("Jobs");
	    assertNotNull(resultPersons);
	    assertEquals(1,resultPersons.size());
	    PersonDTO resultPerson = resultPersons.get(0);
	    assertNotNull(resultPerson);
	    assertTrue(resultPerson.getFirstName().equalsIgnoreCase(testPerson.getFirstName()));
	    assertTrue(resultPerson.getLastName().equalsIgnoreCase(testPerson.getLastName()));
	    assertNull(resultPerson.getCurrentResidence());
	    assertEquals(0, resultPerson.getResidences().size());
	    assertEquals(0, resultPerson.getRegistrations().size());
	    
	    ResidenceDTO testResidence = new ResidenceDTO();
	    testResidence.setStreetNo(123);
	    testResidence.setStreetName("Cool Street");
	    testResidence.setCity("Cleveland");
	    testResidence.setState(State.OH);
	    testResidence.setZipCode(45398);
	    testResidence.setMoveIn(new Date(1234456));
	    testResidence.setMoveOut(null);
	    jndi = runAs(sherriUser,password);
	    driverManager.moveResidence(resultPerson.getId(), testResidence);
	    
	    jndi = runAs(mayberryUser,password);
	    PersonDTO peep3 = driverManager.getDriver(resultPerson.getId());
	    ResidenceDTO resultRes = peep3.getCurrentResidence();
	    assertNotNull(resultRes);
	    assertEquals(testResidence.getStreetNo(), resultRes.getStreetNo());
	    assertEquals(testResidence.getZipCode(), resultRes.getZipCode());
	    assertNull(resultRes.getMoveOut());
	    
	    List<VehicleRegistrationDTO> allCars = carManager.getAllVehicles();
    	assertNotNull(allCars);
    	assertEquals(allCars.size(), 1000);
	    
	    VehicleRegistrationDTO newCar = new VehicleRegistrationDTO();
    	newCar.setMake("WEIRD");
    	newCar.setModel("INTERESTING");
    	newCar.setYear(1987);
    	newCar.setColor(Color.BRONZE);
    	 jndi = runAs(raleighUser,password);
    	carManager.addRegistration(newCar);
    	
    	 jndi = runAs(mayberryUser,password);
    	allCars = carManager.getAllVehicles();
    	assertNotNull(allCars);
    	assertEquals(allCars.size(), 1001);
    	for(VehicleRegistrationDTO car : allCars) {
  		  log.debug("Vehicle: " + car.printSummary());
  		}
    	
    	//Grabbing Steve Jobs and inserting him into Mayberry
    	resultPersons = driverManager.getDriversByLastName("Jobs");
	    assertNotNull(resultPersons);
	    assertEquals(1,resultPersons.size());
	    resultPerson = resultPersons.get(0);
	    jndi = runAs(mayberryUser,password);
	    poiManager.addPOIFromDMV(resultPerson.getId());  
	    jndi = runAs(mayberryUser,password);
	    assertNotNull(poiManager.getAllPOI());
	    assertEquals(poiManager.getAllPOI().size(), 1);
	    POIDTO resultDude = poiManager.getAllPOI().get(0);
	    assertNotNull(resultDude);
	    
	    assertTrue(resultPerson.getFirstName().equalsIgnoreCase(resultDude.getFirstName()));
	    assertTrue(resultPerson.getMiddleName().equalsIgnoreCase(resultDude.getMiddleName()));
	    assertTrue(resultPerson.getLastName().equalsIgnoreCase(resultDude.getLastName()));
	    assertTrue(resultPerson.getPhysicalDetails().getHeight() == resultDude.getHeight());
	    assertTrue(resultPerson.getPhysicalDetails().getWeight() == resultDude.getWeight());
	    
	    ActivityDTO newAct = new ActivityDTO();
	    newAct.setDate(new Date(System.currentTimeMillis()));
	    newAct.setType(Type.ASSAULT);
	    newAct.setDescription("This dude is dangerous");
	    jndi = runAs(barneyUser,password);
	    poiManager.addActivity(resultDude.getId(), newAct);
	    
	    jndi = runAs(gomerUser,password);
	    POIDTO otherDude = poiManager.getPOI(resultDude.getId());
	    assertTrue(resultPerson.getFirstName().equalsIgnoreCase(otherDude.getFirstName()));
	    assertTrue(resultPerson.getMiddleName().equalsIgnoreCase(otherDude.getMiddleName()));
	    assertTrue(resultPerson.getLastName().equalsIgnoreCase(otherDude.getLastName()));
	    assertTrue(resultPerson.getPhysicalDetails().getHeight() == otherDude.getHeight());
	    assertTrue(resultPerson.getPhysicalDetails().getWeight() == otherDude.getWeight());
	    assertTrue(poiManager.isDangerous(otherDude));
	    
	    jndi = runAs(mayberryUser,password);
	    PersonDTO dmvDude = personManager.getPeopleByLastName("Jobs").get(0);
	    assertTrue(dmvDude.getFirstName().equalsIgnoreCase(otherDude.getFirstName()));
	    assertTrue(dmvDude.getMiddleName().equalsIgnoreCase(otherDude.getMiddleName()));
	    assertTrue(dmvDude.getLastName().equalsIgnoreCase(otherDude.getLastName()));
	    assertTrue(dmvDude.getPhysicalDetails().getHeight() == otherDude.getHeight());
	    assertTrue(dmvDude.getPhysicalDetails().getWeight() == otherDude.getWeight());
	    
	    
    }
    
}
